package com.htudata.core.util.operation;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.imageio.stream.ImageOutputStream;
import org.apache.commons.io.FileUtils;

public class FileIOOperationUtils {

  
  public static String readFileToString(File file, String encoding) throws Exception{
    String result = FileUtils.readFileToString(file, encoding);
    return result;
  }
  
  public static List<String> readFileToLineList(String filePath, boolean readEmptyLine, boolean readWrap, String encoding)throws Exception {
    BufferedReader reader = null;
    List<String> result = new ArrayList<>();
    try {
      reader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), encoding));
      String line = reader.readLine();
      while (line != null) {
        if (!readEmptyLine && 
          !StringOperationUtils.isValidStr(line)) {
          line = reader.readLine();
          continue;
        } 
        String wrap = "";
        if (readWrap)
          wrap = "\r\n"; 
        result.add(String.valueOf(line) + wrap);
        line = reader.readLine();
      } 
    } catch (Exception e) {
      throw e;
    } finally {
      close(reader);
    } 
    if (readWrap) {
      int lastIndex = result.size() - 1;
      String lastLine = result.get(lastIndex);
      lastLine = lastLine.substring(0, lastLine.length() - "\r\n".length());
      result.set(lastIndex, lastLine);
    } 
    return result;
  }
  
  public static Map<String, String> readPropertiesToMap(String filePath, String encoding)throws Exception {
    BufferedReader reader = null;
    Map<String, String> result = new LinkedHashMap<>();
    try {
      reader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), encoding));
      String line = reader.readLine();
      int equalIndex = 0;
      String key = "";
      String value = "";
      while (line != null) {
        if (!StringOperationUtils.isValidStr(line)) {
          line = reader.readLine();
          continue;
        } 
        equalIndex = line.indexOf("=");
        if (equalIndex == -1) {
          line = reader.readLine();
          continue;
        } 
        key = line.substring(0, equalIndex);
        value = line.substring(equalIndex + 1);
        result.put(key, value);
        line = reader.readLine();
      } 
      return result;
    }  catch (Exception e) {
       throw e;
    } finally {
      close(reader);
    }
  }
  
  public static String readInputStreamToString(InputStream in, String encoding) throws Exception{
    ByteArrayOutputStream byteArrayOutputStream = getByteArrayOutputStreamFromInputStream(in);
    try {
      String result = byteArrayOutputStream.toString(encoding);
      return result;
    } catch (Exception e) {
      throw e;
    } finally {
      close(byteArrayOutputStream);
    }
  }
  
  public static byte[] readByteArrFromInputStream(InputStream in) throws Exception{
    ByteArrayOutputStream byteArrayOutputStream = getByteArrayOutputStreamFromInputStream(in);
    byte[] result = byteArrayOutputStream.toByteArray();
    close(byteArrayOutputStream);
    return result;
  }
  
  public static ByteArrayOutputStream getByteArrayOutputStreamFromInputStream(InputStream in) throws Exception{
    try {
      ByteArrayOutputStream result = new ByteArrayOutputStream();
      byte[] byteArr = new byte[in.available()];
      int len = 0;
      while ((len = in.read(byteArr)) != -1)
        result.write(byteArr, 0, len); 
      return result;
    } catch (Exception e) {
      throw e;
    } 
  }
  
  public static boolean writeStringToFile(File file, String content, String encoding)throws Exception {
    FileUtils.writeStringToFile(file, content, encoding);
    return true;
  }
  
  public static boolean writeLineListToFile(String filePath, List<String> lineList, String encoding) throws Exception {
    BufferedWriter writer = null;
    try {
      writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath), encoding));
      for (String line : lineList)
        writer.write(line); 
      return true;
    }  catch (Exception e) {
      throw e;
    } finally {
      close(writer);
    }
  }
  
  public static <T> boolean writeTwoDimensionalArrToFile(Object[][] arr, String filePath, String encoding) throws Exception{
    List<String> lineList = new ArrayList<>();
    long arrLength = arr.length;
    long arrChlidLength = 0L;
    String line = "";
    for (int i = 0; i < arrLength; i++) {
      line = "";
      arrChlidLength = (arr[i]).length;
      for (int j = 0; j < arrChlidLength; j++)
        line = String.valueOf(line) + arr[i][j] + " "; 
      line = String.valueOf(line) + "\r\n";
      lineList.add(line);
    } 
    return writeLineListToFile(filePath, lineList, encoding);
  }
  
  public static boolean writeByteArrToFile(byte[] byteArr, String fileSavePath) throws Exception {
    FileOutputStream out = null;
    try {
      out = new FileOutputStream(fileSavePath);
      out.write(byteArr);
      out.flush();
      return true;
    } catch (Exception e) {
      throw e;
    } finally {
      try {
        if (out != null) {
          out.close();
          out = null;
        } 
      } catch (IOException e) {

      } 
    }
  }
  
  public static boolean copy(String srcFilePath, String tgtFilePath) throws Exception{
    FileInputStream in = null;
    FileOutputStream out = null;
    FileChannel fileChannelIn = null;
    FileChannel fileChannelOut = null;
    try {
      in = new FileInputStream(srcFilePath);
      out = new FileOutputStream(tgtFilePath);
      fileChannelIn = in.getChannel();
      fileChannelOut = out.getChannel();
      fileChannelIn.transferTo(0L, fileChannelIn.size(), fileChannelOut);
      return true;
    }  catch (Exception e) {
       throw e;
    } finally {
      close(fileChannelOut);
      close(out);
      close(fileChannelIn);
      close(in);
    }
  }
  
  public static void close(OutputStream out)  {
    try {
      if (out != null) {
        out.close();
        out = null;
      } 
    } catch (IOException e) {

    } 
  }
  
  public static void close(ImageOutputStream out)   {
    try {
      if (out != null) {
        out.close();
        out = null;
      } 
    } catch (IOException e) {

    } 
  }
  
  public static void close(InputStream in)  {
    try {
      if (in != null) {
        in.close();
        in = null;
      } 
    } catch (IOException e) {

    } 
  }
  
  public static void close(Writer writer) {
    try {
      if (writer != null) {
        writer.close();
        writer = null;
      } 
    } catch (IOException e) {

    } 
  }
  
  public static void close(Reader reader) {
    try {
      if (reader != null) {
        reader.close();
        reader = null;
      } 
    } catch (IOException e) {

    } 
  }
  
  public static void close(FileChannel fileChannel) {
    try {
      if (fileChannel != null) {
        fileChannel.close();
        fileChannel = null;
      } 
    } catch (IOException e) {

    } 
  }
}
